/*
 * A.cpp
 *
 *  Created on: May 22, 2011
 *      Author: federico
 */

#include "A.h"

A::A()
{
}

A::A(Manhattan15Puzzle *manhattanCalculator)
{

	this->manhattanCalculator = manhattanCalculator;

}

A::A(PDBHeuristic *fpdb, PDBHeuristic *spdb, PDBHeuristic *tpdb)
{

	this->fpdb = fpdb;
	this->spdb = spdb;
	this->spdb = tpdb;

}

void A::run(FifteenPuzzleNodeA *So)
{
	open = new OpenList();
	open->insert(So);
	openclose = new Hash();
	openclose->insert(Hash::value_type(So->permutationRank + So->dBoard[0] + So->dBoard[1], So));

	FifteenPuzzleNodeA *S;

	while((S = open->pullMax()) != NULL) //Hay que hacer la actualizacion de las posiciones aca, pero revisando el codigo como que se haec, pero porsia dejo la anotacion.
	{
		if(S->getH() == 0)
		{
			cout << "Mejor solucion de costo " << S->getG() << " | ";
			cout << "Nodos expandidos " << openclose->size();

			Hash::iterator eraser = openclose->begin();
			for(; eraser != openclose->end(); eraser++)
			{

				delete (eraser->second);
				//
			}

			delete(openclose);
			delete(open);
			return;
		}

		//Yo puse char ya que ese era el primer plan jeje. Pero avisame que pongo si int, char u otra vaina.
		//Aca va la parte de pasarle la clase Manhattan para que actualice sus heuristicas en los sucesores. No se como prefieras implementarlo, lo dejo asi por ahora por eso.
		vector<FifteenPuzzleNodeA *> succs;

		if(heuristic == Manhattan)
			succs = S->getSuccesors(manhattanCalculator);
		else
			succs = S->getSuccesors(fpdb, spdb, tpdb);

		vector<FifteenPuzzleNodeA *>::iterator it;
		/*
		cout <<"Padre es: \n";
		S->printBoard();
		cout <<"Con H: "<< S->getH() <<"\n";
		cout <<"Con G: "<< S->getG() <<"\n";
		cout <<"Con F: "<< S->getF() <<"\n";*/

		for(it = succs.begin(); it != succs.end(); it++)
		{/*
			cout <<"Hijo es: ";
			(*it)->printBoard();
			cout <<"Con H: "<< (*it)->getH() <<"\n";
			cout <<"Con G: "<< (*it)->getG() <<"\n";
			cout <<"Con F: "<< (*it)->getF() <<"\n"; */


			Hash::iterator pos = openclose->find((*it)->permutationRank + (*it)->dBoard[0] + (*it)->dBoard[1]);
			bool finded = false;

			for(; pos != openclose->end() && (*it)->permutationRank + (*it)->dBoard[0] + (*it)->dBoard[1] == pos->first; pos++)
			{


				if(pos->second->dBoard[0] == (*it)->dBoard[0] && pos->second->dBoard[1] == (*it)->dBoard[1] && pos->second->permutationRank == (*it)->permutationRank)
				{
					finded = true;
					break;
				}

			}

			if(!finded)
			{
				open->insert(*it);
				openclose->insert(Hash::value_type((*it)->permutationRank  + (*it)->dBoard[0] + (*it)->dBoard[1] , *it));
			}
			else{
				if(pos->second->getHeapIndex() != UINT_MAX)
				{
					if((*it)->getG() < pos->second->getG())
					{
						open->changeCost(pos->second, (*it)->getG()); //Los de las posiciones aca tambien, por lo visto el insert lo hace, pero porsia dejo la anotacion.
						pos->second->setFatherMovements((*it)->getFatherMovements());// Cambiando el papá
					}
					delete(*it);
				}
				else if((*it)->getG() < pos->second->getG())
				{
					open->insert(*it);
					openclose->erase(pos);
					openclose->insert(Hash::value_type((*it)->permutationRank  + (*it)->dBoard[0] + (*it)->dBoard[1], *it));

				}
				else delete(*it);
			}

			//Para el if que queda, con la manhattan no es necesario ya que es consistente, pero los PDB Blai nunca dijo que ni si ni no, asi que hay que ponerlo

		}

	}


}

A::~A()
{
}
